package com.quanyan.orderpay.service.impl;

import com.alibaba.fastjson.JSON;
import com.google.common.reflect.TypeToken;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.quanyan.alipay.config.AlipayConfig;
import com.quanyan.alipay.protocal.*;
import com.quanyan.api.APIRequest;
import com.quanyan.api.APIResponse;
import com.quanyan.api.enums.ApiResponseEnum;
import com.quanyan.assets.entity.TbUserAssets;
import com.quanyan.assets.request.*;
import com.quanyan.assets.response.RespUserAccumulateHistory;
import com.quanyan.assets.service.CouponService;
import com.quanyan.assets.service.CurrencyService;
import com.quanyan.assets.service.UserAssetsService;
import com.quanyan.common.Plugin.Page;
import com.quanyan.common.Plugin.PageObj;
import com.quanyan.common.constants.Constants;
import com.quanyan.common.encrypt.AESCoder;
import com.quanyan.common.http.HttpClientUtils;
import com.quanyan.common.utils.*;
import com.quanyan.mq.client.QcMsgClient;
import com.quanyan.mq.client.reqeust.MqRequestMsg;
import com.quanyan.order.entity.Order;
import com.quanyan.order.entity.OrderExample;
import com.quanyan.order.entity.OrderMq;
import com.quanyan.order.entity.OrderMqExample;
import com.quanyan.order.enums.OrderStatusEnum;
import com.quanyan.order.mapper.EOrderMqMapper;
import com.quanyan.order.mapper.OrderMapper;
import com.quanyan.order.mapper.OrderMqMapper;
import com.quanyan.order.mapper.UOrderMapper;
import com.quanyan.order.service.OrderService;
import com.quanyan.order.vo.TimeoutOrderVo;
import com.quanyan.orderpay.component.OrderPayRedisTemplate;
import com.quanyan.orderpay.constants.OrderMqConstants;
import com.quanyan.orderpay.entity.BackInfo;
import com.quanyan.orderpay.entity.PaySuccessData;
import com.quanyan.orderpay.request.ReqBatchWithdrawQuery;
import com.quanyan.orderpay.request.ReqOrderRefund;
import com.quanyan.orderpay.request.ReqPayInfo;
import com.quanyan.orderpay.request.WithdrawPayInfo;
import com.quanyan.orderpay.response.RespBatchWithdraw;
import com.quanyan.orderpay.response.RespWithdrawApply;
import com.quanyan.orderpay.response.mq.*;
import com.quanyan.orderpay.service.OrderPayService;
import com.quanyan.orderpay.service.OrderProcessService;
import com.quanyan.pay.component.alipay.AlipayComponent;
import com.quanyan.pay.component.weichat.WeiChatComponent;
import com.quanyan.pay.entity.*;
import com.quanyan.pay.enums.PayWayEnum;
import com.quanyan.pay.enums.RefundStatusEnum;
import com.quanyan.pay.enums.TradeTypeEnum;
import com.quanyan.pay.exception.RespPayEnum;
import com.quanyan.pay.mapper.*;
import com.quanyan.pay.service.AccountPayRelationService;
import com.quanyan.pay.service.PayConfigService;
import com.quanyan.pay.service.PayService;
import com.quanyan.pay.service.WeichatAccountService;
import com.quanyan.weichat.api.WeichatServiceApi;
import com.quanyan.weichat.common.*;
import com.quanyan.weichat.common.Configure;
import com.quanyan.weichat.protocol.closeorder_protocal.CloseOrdeReqData;
import com.quanyan.weichat.protocol.pay_protocol.WXScanPayReqData;
import com.quanyan.weichat.protocol.transfer_fund_protocal.TransferFundReqData;
import com.quanyan.weichat.protocol.transfer_fund_protocal.TransferFundResData;
import org.apache.commons.lang.math.NumberUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.validation.Valid;
import java.io.ByteArrayInputStream;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 订单支付成功后处理
 *
 * @author songzj
 * @date 16/6/7-15:57
 */
@Service("orderProcessService")
public class OrderProcessServiceImpl implements OrderProcessService {

    private Logger logger = LoggerFactory.getLogger(OrderProcessServiceImpl.class);
    private Integer expiredOrderCheckTaskCount = 1;

    @Autowired
    private WeichatAccountMapper weichatAccountMapper;
    @Autowired
    private OrderService orderService;
    @Autowired
    private PayService payService;
    @Autowired
    private CurrencyService currencyService;
    @Autowired
    private UserAssetsService userAssetsService;
    @Autowired
    private QcMsgClient qcMsgClient;
    @Autowired
    private WithdrawApplyMapper withdrawApplyMapper;
    @Autowired
    private WithdrawRecordMapper withdrawRecordMapper;
    @Autowired
    private TSNRecordMapper tsnRecordMapper;
    @Autowired
    private WeiChatComponent weiChatComponent;
    @Autowired
    private RefundRecordMapper refundRecordMapper;
    @Autowired
    private OrderMqMapper orderMqMapper;
    @Autowired
    private EOrderMqMapper eOrderMqMapper;
    @Autowired
    private UOrderMapper uOrderMapper;
    @Autowired
    private AccountPayRelationService accountPayRelationService;
    @Autowired
    private WeichatAccountService weichatAccountService;
    @Autowired
    private AlipayComponent alipayComponent;
    @Autowired
    private PayConfigService payConfigService;
    @Autowired
    private OrderPayService orderPayService;
    @Autowired
    private CouponService couponService;
    @Autowired
    private OrderPayRedisTemplate orderPayRedisTemplate;
    @Autowired
    private OrderMapper orderMapper;
    @Autowired
    private PayRecordMapper payRecordMapper;
    @Autowired
    private EWithdrawBatchMapper eWithdrawBatchMapper;
    @Autowired
    private WithdrawBatchMapper withdrawBatchMapper;
    @Autowired
    private EWithdrawApplyMapper eWithdrawApplyMapper;
    @Autowired
    private UPayRecordMapper uPayRecordMapper;
    @Override
    @Transactional
    public boolean paySuccess(PaySuccessData paySuccessData) {
        String orderNo = paySuccessData.getOrderNo();

        PayRecord payRecord = this.payService.selectPayRecordByOrderNo(orderNo);
        //校验金额.
        if (payRecord == null || (null!=paySuccessData.getPayAmount()&&paySuccessData.getPayAmount().compareTo(payRecord.getPayAmount()) != 0)) {
            logger.warn("校验金额异常");
            return false;
        }
        // 更新tb_pay_record表
        APIResponse<RespPayEnum> apiResponse = this.payService.updatePaySuccessProcess(paySuccessData.getTsn(), orderNo,
                paySuccessData.getPayTime(),
                0, paySuccessData.getBuyerId(), paySuccessData.getBuyerAccount(), paySuccessData.getBuyerBank(), paySuccessData.getSellerId(), paySuccessData.getSellerAccount());
        logger.warn("更新tb_pay_record表成功");
        // 更新tb_order表
        if(payRecord.getPayId().equals(PayWayEnum.PAY_WAY_ALIPAY_H5.getPayId())||payRecord.getPayId().equals(PayWayEnum.PAY_WAY_ALIPAY_SCAN_CODE.getPayId())){
            paySuccessData.setTradeType(TradeTypeEnum.getByPayId(payRecord.getPayId()));
        }
        this.orderService.updateOrderPaySuccess(orderNo, paySuccessData.getTradeType().getPayId(),
                paySuccessData.getTradeType().getPayType(), paySuccessData.getPayTime());
        logger.warn("更新tb_order表成功");
        Order order = this.orderService.selectOrderByOrderNo(null, orderNo);
        if(null!=order.getOrderState()&&order.getOrderState().equals(OrderStatusEnum.ORDER_STAE_CLOSED.getId())){
            logger.warn("异常订单:"+order.getOrderNo());
            if(!paySuccessData.getTradeType().getPayId().equals(PayWayEnum.PAY_WAY_UNION_PAY_POS.getPayId())){
                //订单关闭又支付成功,异常订单主动退款第三方
                APIRequest<ReqOrderRefund> apiRequest=new APIRequest<ReqOrderRefund>();
                ReqOrderRefund reqOrderRefund=new ReqOrderRefund();
                reqOrderRefund.setNeedAudit(false);
                reqOrderRefund.setOrderNo(order.getOrderNo());
                reqOrderRefund.setOutTradeNo(order.getOrderNo());
                reqOrderRefund.setOutTradeRefundNo(order.getOutTradeNo());
                reqOrderRefund.setReason(payService.PAY_CLOSE_EXCEPTION);
                reqOrderRefund.setRefundProductList(orderService.selectOrderProductByOrderNo(order.getId()));
                reqOrderRefund.setReqRefundPayInfos(payService.selectThreePayDetailByOrderNo(order.getOrderNo()));
                reqOrderRefund.setSourceSystemId(order.getSourceSystemId());
                reqOrderRefund.setSourceBusinessId(order.getSourceBusinessId());
                reqOrderRefund.setUid(order.getUid());
                apiRequest.setData(reqOrderRefund);
                APIResponse<RefundStatusEnum> apiResponse1=orderPayService.refundApply(apiRequest);
                if(apiResponse1.getData().equals(RefundStatusEnum.APPLY_SUBMIT)){
                    //申请成功
                    sendMessageToMQrefundApply(order.getOrderNo());
                }else{
                    //补偿
                }
            }else{
                //支付方式为银联pos时，订单超时又支付记日志
                logger.error("银联POS订单超时又支付，参数{}", GsonUtils.toJson(paySuccessData));
            }

        }else{
            logger.warn("正常订单:"+order.getOrderNo());
            unfrezenUserAssest(order,"SUCCESS");
            logger.warn("解冻资产完成");
            //支付金额
            if(!paySuccessData.getTradeType().getPayId().equals(PayWayEnum.PAY_WAY_FOR_FREE.getPayId())){
                if(paySuccessData.getTradeType().getPayId().equals(PayWayEnum.PAY_WAY_ALIPAY_SCAN.getPayId())||
                        paySuccessData.getTradeType().getPayId().equals(PayWayEnum.PAY_WAY_WEICHAT_SCAN.getPayId())){
                    callBackScanPay(paySuccessData);
                }else{
                    sendMessageToMQ(paySuccessData);
                }

            }

        }

        return true;
    }




    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean refundComplateProcess(RefundCompleteData refundCompleteData) {
        //退款记录更新
        APIResponse payApiResponse = this.payService.refundCompleteProcess(refundCompleteData);
        //退款订单记录更新
        APIResponse orderApiResponse=this.orderService.refundCompleteProcess(refundCompleteData.getRefundOrderNo(), refundCompleteData.getResult());
        //消息通知
        if(refundCompleteData.getResult().equals(RefundStatusEnum.SUCCESS.getCode())||
                refundCompleteData.getResult().equals(RefundStatusEnum.FAIL.getCode())||
                refundCompleteData.getResult().equals(RefundStatusEnum.CHANGE.getCode())) {
            RefundRecordExample refundRecordExample=new RefundRecordExample();
            refundRecordExample.createCriteria().andRefundOrderNoEqualTo(refundCompleteData.getRefundOrderNo());
            List<RefundRecord> refundRecordList=refundRecordMapper.selectByExample(refundRecordExample);
            if(!refundRecordList.isEmpty()) {
                RefundNotifyMsg refundNotifyMsg = new RefundNotifyMsg();
                refundNotifyMsg.setRefundState(refundRecordList.get(0).getRefundState());
                refundNotifyMsg.setRefundMsg(refundRecordList.get(0).getRefundMsg());
                //   refundNotifyMsg.setRefundTime(refundRecordList.get(0).getRefundTime());
                refundNotifyMsg.setOrderNo(refundRecordList.get(0).getOrderNo());
                refundNotifyMsg.setRefundOrderNo(refundRecordList.get(0).getRefundOrderNo());
                refundNotifyMsg.setOutTradeRefundOrderNo(refundRecordList.get(0).getOutTradeRefundNo());
                refundNotifyMsg.setOrderAmount(refundRecordList.get(0).getOrderAmount());
                refundNotifyMsg.setRefundAmount(refundRecordList.get(0).getRefundAmount());
                refundNotifyMsg.setRefundChannel(refundRecordList.get(0).getRefundChannel());
                refundNotifyMsg.setRefundRecvAccount(refundRecordList.get(0).getRefundRecvAccount());
                if(null!=refundRecordList.get(0).getReason()&&refundRecordList.get(0).getReason().equals(payService.PAY_CLOSE_EXCEPTION)){
                    refundNotifyMsg.setExceptionFlag(true);
                }else{
                    refundNotifyMsg.setExceptionFlag(false);
                }
                sendMessageToMQ(refundNotifyMsg);
            }
        }
        return true;

    }

    public void unfrezenUserAssest(Order order,String result) {
        //判断用户是否使用鸟蛋.
        List<PayRecordDetail> list = this.payService.selectPayRecordDetailByOrderNo(order.getOrderNo());
        ReqUnfreezeOrder reqUnfreezeOrder=new ReqUnfreezeOrder();
        APIRequest apiRequest=new APIRequest();
        for (PayRecordDetail payRecordDetail : list) {
            if (payRecordDetail.getPayId().equals(PayWayEnum.PAY_WAY_FOR_AGES.getPayId()) || payRecordDetail.getPayId().equals(PayWayEnum.PAY_WAY_FOR_SHELL.getPayId())) {
                ReqUnfreeze reqUnfreeze = new ReqUnfreeze();
                reqUnfreeze.setSystemCode(order.getSourceSystemId());
                reqUnfreeze.setBusinessCode(order.getSourceBusinessId());
                reqUnfreeze.setBusinessNo(order.getOutTradeNo());
                reqUnfreezeOrder.setReqUnfreeze(reqUnfreeze);
                //  APIResponse accumulateResponse = this.userAssetsService.unfreezeAccumulateSuccess(apiRequest);
                //

            }else if(payRecordDetail.getPayId().equals(PayWayEnum.PAY_WAY_FOR_COUPON.getPayId())){
                ReqCoupon reqCoupon=new ReqCoupon();
                reqCoupon.setActualAmount(payRecordDetail.getPayAmount());
                reqCoupon.setCouponCode(payRecordDetail.getSubjectCode());
                reqUnfreezeOrder.setReqCoupon(reqCoupon);
            }
        }
        apiRequest.setData(reqUnfreezeOrder);
        if(null!=reqUnfreezeOrder){
            if(result.equals("SUCCESS")) {
                APIResponse apiResponse = this.userAssetsService.unfreezeSuccess(apiRequest);
                logger.info("订单 {} 支付成功后解冻资产 {}!。请求{}，晌应{}。", order.getOrderNo(), apiResponse.isRet(), GsonUtils.toJson(apiRequest), GsonUtils.toJson(apiResponse));
            }else if(result.equals("FAIL")){
                APIResponse apiResponse = this.userAssetsService.unfreezeFail(apiRequest);
                logger.info("订单 {} 超时未支付后解冻资产 {}!请求{}，晌应{}。", order.getOrderNo(), apiResponse.isRet(), GsonUtils.toJson(apiRequest), GsonUtils.toJson(apiResponse));
            }
        }
    }

    @Override
    public void refreshAccessToken() {
        logger.warn(String.format("定期刷新access_token，第%s次执行，当前时间为：%s", expiredOrderCheckTaskCount++, TimeUtils.getSimpleFullEngString(new Date())));
        try {
            WeichatAccountExample example = new WeichatAccountExample();
            WeichatAccountExample.Criteria criteria = example.createCriteria();
            criteria.andTypeEqualTo("H5");
            List<WeichatAccount> weichatAccounts = weichatAccountMapper.selectByExample(example);
            for (int i = 0; i < weichatAccounts.size(); i++) {
                WeichatAccount weichatAccount = weichatAccounts.get(i);
                String appId = weichatAccount.getAppId();
                String securityKey = AESCoder.decodeContent(weichatAccount.getSecurityKey());
                WeichatServiceApi api = new WeichatServiceApi();
                Map<String, String> tokenMap = api.refreshToken(appId, securityKey);
                if (!tokenMap.get("result").equals("true")) {
                    tokenMap = api.refreshToken(appId, securityKey);
                }

                if (tokenMap.get("result").equals("true")) {
                    orderPayRedisTemplate.hmset("token_" + appId, tokenMap);
                }
                String token = tokenMap.get("access_token");

                Map<String, String> ticktMap = api.refreshJsApiTiket(token);
                if (!ticktMap.get("result").equals("true")) {
                    ticktMap = api.refreshJsApiTiket(token);
                }


                if (ticktMap.get("result").equals("true")) {
                    orderPayRedisTemplate.hmset("ticket_" + appId, ticktMap);
                }
                String access_token = orderPayRedisTemplate.hget("token_" + appId, "access_token");
                String ticket = orderPayRedisTemplate.hget("ticket_" + appId, "ticket");
                logger.warn("appId>>>>>>"+appId+"  access_token>>>>"+access_token+"   ticket>>>>>"+ticket);

            }
        } catch (Exception e) {
            logger.error("查询access_token异常");
        }
    }



    /**
     * 解冻资产
     * @return
     */
    private boolean unfrezenUserAssestSuccess(String systemCode, String businessCode, String businessNo) {
        //解冻资产
        ReqUnfreeze reqUnfreeze = new ReqUnfreeze();
        reqUnfreeze.setSystemCode(systemCode);
        reqUnfreeze.setBusinessCode(businessCode);
        reqUnfreeze.setBusinessNo(businessNo);
        APIRequest<ReqUnfreeze> reqUnfreezeAPIRequest = new APIRequest<>();
        reqUnfreezeAPIRequest.setData(reqUnfreeze);
        APIResponse<List<TbUserAssets>>  listAPIResponse = userAssetsService.unfreezeAccumulateFail(reqUnfreezeAPIRequest);
        if (listAPIResponse.isRet()) {
            return true;
        }
        logger.info("定时任务关闭超时订单-解冻资产失败。请求{}，晌应{}。", GsonUtils.toJson(reqUnfreezeAPIRequest), GsonUtils.toJson(listAPIResponse));

        return false;
    }

    @Override
    @Transactional(isolation = Isolation.READ_COMMITTED, propagation = Propagation.REQUIRED)
    public void orderQuery() {
        List<Integer> payList = new ArrayList<Integer>();
        payList.add(PayWayEnum.PAY_WAY_WEICHAT_SCAN.getPayId());
        payList.add(PayWayEnum.PAY_WAY_ALIPAY_SCAN.getPayId());
        List<Byte> orderStateList = new ArrayList<Byte>();
        orderStateList.add(OrderStatusEnum.ORDER_STATE_UNCHECKED.getId());
        orderStateList.add(OrderStatusEnum.ORDER_STATE_CHECKED.getId());
        OrderExample orderExample = new OrderExample();
        orderExample.createCriteria().andPayStateEqualTo(OrderStatusEnum.ORDER_STATE_UNCHECKED.getId())
                .andPayIdIn(payList).andOrderStateIn(orderStateList);
        List<Order> orderList=orderMapper.selectByExample(orderExample);
        for(Order order:orderList){
            if(order.getPayId().equals(PayWayEnum.PAY_WAY_WEICHAT_SCAN.getPayId())){
                //微信扫描枪订单查询
                Map<String, String> map = payService.getWeichatOrderStatusByOrderNo(order.getOrderNo());
                if (map != null && map.get("trade_state").equals("SUCCESS")) {
                    //支付成功后处理
                    PaySuccessData paySuccessData = new PaySuccessData();
                    paySuccessData.setBuyerAccount(map.get("openid"));
                    paySuccessData.setBuyerBank(map.get("bank_type"));
                    paySuccessData.setBuyerId(null);
                    paySuccessData.setOrderNo(order.getOrderNo());
                    paySuccessData.setTsn(map.get("transaction_id"));
                    paySuccessData.setPayAmount(new BigDecimal(map.get("total_fee")).divide(new BigDecimal("100"), 2, BigDecimal.ROUND_HALF_DOWN));
                    paySuccessData.setPayTime(DateTimeUtils.convertString2Date("yyyyMMddHHmmss", map.get("time_end")));
                    paySuccessData.setSourceType(OrderMqConstants.PAY_RESEND);
                    paySuccessData.setTradeType(TradeTypeEnum.TRADE_TYPE_WEICHAT_SCAN);
                    paySuccess(paySuccessData);
                }
            }else if(order.getPayId().equals(PayWayEnum.PAY_WAY_ALIPAY_SCAN.getPayId())){
                //支付宝扫描枪订单查询
                AlipayConfig alipayConfig = payConfigService.getAlipayConfig(order.getMchId().toString(), order.getPayId().intValue());
                AliPayTradeQueryReq aliPayTradeQuery = new AliPayTradeQueryReq();
                aliPayTradeQuery.setOut_trade_no(order.getOrderNo());
                APIResponse<AliPayTradeQueryResp> apiResponse=alipayComponent.tradeQuery(aliPayTradeQuery,alipayConfig);
                if(apiResponse.isRet()&&null!=apiResponse.getData()
                        &&"TRADE_SUCCESS".equals(apiResponse.getData().getAlipayTradeQueryResponse().getTrade_status())){
                    //支付成功后处理
                    PaySuccessData paySuccessData = new PaySuccessData();
                    paySuccessData.setBuyerAccount(apiResponse.getData().getAlipayTradeQueryResponse().getBuyer_user_id());
                    paySuccessData.setBuyerId(apiResponse.getData().getAlipayTradeQueryResponse().getBuyer_logon_id());
                    paySuccessData.setPayTime(apiResponse.getData().getAlipayTradeQueryResponse().getSend_pay_date());
                    paySuccessData.setPayAmount(apiResponse.getData().getAlipayTradeQueryResponse().getTotal_amount());
                    paySuccessData.setBuyerBank("");
                    paySuccessData.setBuyerId(null);
                    paySuccessData.setOrderNo(order.getOrderNo());
                    paySuccessData.setTsn(apiResponse.getData().getAlipayTradeQueryResponse().getTrade_no());
                    paySuccessData.setSourceType(OrderMqConstants.PAY_RESEND);
                    paySuccessData.setTradeType(TradeTypeEnum.TRADE_TYPE_ALIPAY_SCAN);
                    paySuccessData.setSellerId(alipayConfig.getPartner());
                    paySuccessData.setSellerAccount(alipayConfig.getSeller());
                    paySuccess(paySuccessData);
                }
            }


        }

    }

    @Override
    @Transactional(isolation = Isolation.READ_COMMITTED, propagation = Propagation.REQUIRED)
    public void scanPay() {
        List<PayRecord> payRecordList = uPayRecordMapper.scanPayRepair();
        for(PayRecord payRecord : payRecordList){
            //支付宝移动支付订单查询
            AlipayConfig alipayConfig = payConfigService.getAlipayConfig(payRecord.getMchId().toString(), payRecord.getPayId().intValue());
            AliRespQueryTrade aliRespQueryTrade = alipayComponent.queryTrade(payRecord.getOrderNo(), alipayConfig);
            if ("T".equals(aliRespQueryTrade.getIs_success())) {
                PayRecord updatePayRecord = new PayRecord();
                updatePayRecord.setBuyerLoginAccount(aliRespQueryTrade.getResponse().get(0).getBuyer_email());
                updatePayRecord.setBuyerId(aliRespQueryTrade.getResponse().get(0).getBuyer_email());

                updatePayRecord.setOrderNo(payRecord.getOrderNo());
                uPayRecordMapper.updateScanPayRecord(updatePayRecord);
            }

        }

    }

    @Override
    public boolean refundComplateProcess() {
        //获取退款中订单.
        int pageNo = 0;
        APIResponse<PageObj<List<RefundRecord>>> refundRecords = this.payService.refundWechatStatusQuery(pageNo);
        //退款完成数据封装和处理
        refundIngProcess(refundRecords);
        for (; ++pageNo <= refundRecords.getData().getPageCount(); ) {
            refundRecords = this.payService.refundWechatStatusQuery(pageNo);
            refundIngProcess(refundRecords);
        }
        return true;
    }

    private void refundIngProcess(APIResponse<PageObj<List<RefundRecord>>> refundRecords) {
        PageObj<List<RefundRecord>> listPageObj = refundRecords.getData();
        if (listPageObj.getItems().isEmpty()) {
            return;
        }
        //已退款结束处理.
        for (RefundRecord refundRecord : listPageObj.getItems()) {
            try {
                processRefundIng(refundRecord);
            } catch (Exception e) {
                logger.error("退款订单查询失败", e);
            }
        }
    }

    @Transactional(isolation = Isolation.READ_COMMITTED, rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    private void processRefundIng(RefundRecord refundRecord) {
        logger.warn("退款订单号<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"+refundRecord.getOrderNo());
        APIResponse<Configure> configureAPIResponse = this.payService.getWeichatAccount(refundRecord.getAppId(), refundRecord.getMchAccount());
        Map<String, String> map = this.weiChatComponent.refundOrderStatusQuery(refundRecord.getOrderNo(), refundRecord.getRefundOrderNo(), configureAPIResponse.getData());
        //退款完成处理
        RefundCompleteData refundCompleteData=new RefundCompleteData();
        refundCompleteData.setRefundId(map.get("refund_id_0"));
        refundCompleteData.setRefundChannel(map.get("refund_channel_0"));
        refundCompleteData.setRefundRecvAccount(map.get("refund_recv_accout_0"));
        refundCompleteData.setRefundOrderNo(refundRecord.getRefundOrderNo());
        refundCompleteData.setOrderNo(refundRecord.getOrderNo());
        refundCompleteData.setResult(map.get("refund_status_0"));
        refundCompleteData.setRefundTime(DateTimeUtils.convertString2Date("yyyy-MM-dd HH:mm:ss", map.get("refund_success_time_0")));
        refundCompleteData.setPayId(PayWayEnum.PAY_WAY_WEICHAT.getPayId());
        BigDecimal refundFee = new BigDecimal(map.get("refund_fee_0")).divide(new BigDecimal("100"), 2, BigDecimal.ROUND_HALF_DOWN);
        refundCompleteData.setRefundAmount(refundFee);
        refundCompleteData.setErrCode(map.get("err_code"));
        refundCompleteData.setErrCodeDes(map.get("err_code_des"));
        refundComplateProcess(refundCompleteData);
    }

    private void sendMessageToMQrefundApply(String orderNo) {
        Order order = this.orderService.selectOrderByOrderNo(null, orderNo);
        List<RefundRecord> refundRecordList=this.payService.selectRefundRecordByOrderNo(orderNo);
        RefundRecord refundRecord=refundRecordList.get(0);
        List<RespRefundPayInfo> respRefundPayInfos = this.payService.selectRefundPayInfoList(refundRecord.getRefundOrderNo());
        RefundNotifyMsg refundNotifyMsg=new RefundNotifyMsg();
        refundNotifyMsg.setSystemCode(order.getSourceSystemId());
        refundNotifyMsg.setBusinessCode(order.getSourceBusinessId());
        refundNotifyMsg.setRefundPayInfos(respRefundPayInfos);
        refundNotifyMsg.setOutTradeNo(order.getOutTradeNo());
        refundNotifyMsg.setUid(order.getUid());
        refundNotifyMsg.setRefundState(refundRecord.getRefundState());
        refundNotifyMsg.setRefundMsg(refundRecord.getRefundMsg());
        refundNotifyMsg.setRefundTime(refundRecord.getRefundTime().getTime());
        refundNotifyMsg.setOrderNo(refundRecord.getOrderNo());
        refundNotifyMsg.setRefundOrderNo(refundRecord.getRefundOrderNo());
        refundNotifyMsg.setOutTradeRefundOrderNo(refundRecord.getOutTradeRefundNo());
        refundNotifyMsg.setOrderAmount(refundRecord.getOrderAmount());
        refundNotifyMsg.setRefundAmount(refundRecord.getRefundAmount());
        refundNotifyMsg.setRefundChannel(refundRecord.getRefundChannel());
        refundNotifyMsg.setRefundRecvAccount(refundRecord.getRefundRecvAccount());
        boolean flag=true;
        Gson gson = new GsonBuilder().create();
        System.out.println(gson.toJson(refundNotifyMsg));
        if (!StringUtil.isBlankOrNull(order.getExceptionRefundNotify()) && HttpUtils.isValidURL(order.getExceptionRefundNotify())) {
            try{
                logger.warn("回调接口:"+order.getExceptionRefundNotify()+"参数:"+gson.toJson(refundNotifyMsg));
                String result=HttpUtils.sendWebRequestByPostJsonStr(null, order.getExceptionRefundNotify(), gson.toJson(refundNotifyMsg));
                logger.warn("回调接口:"+order.getExceptionRefundNotify()+"返回值:"+result);
                java.lang.reflect.Type type = new TypeToken<BackInfo>() {
                }.getType();
                BackInfo backInfo = gson.fromJson(result, type);
                if (null==backInfo||!(backInfo.getRet() && backInfo.getErrcode().equals(200))) {
                    flag = false;
                }else{
                    //通知业务系统成功
                    eOrderMqMapper.updateSuccess(order.getOrderNo(),OrderCallBackMsg.REFUND_SUBMIT);
                }
            }catch (Exception e){
                return;
            }
        } else {
            MqRequestMsg mqRequestMsg = new MqRequestMsg();
            mqRequestMsg.setTopic(OrderPayService.TOPIC_ORDER_REFUND_SUBMIT_NOTIFY); //退款申请成功通知.
            mqRequestMsg.setTag(order.getSourceSystemId());
            mqRequestMsg.setMsgId(refundNotifyMsg.getOutTradeRefundOrderNo()); //外部退款订单号
            mqRequestMsg.setFlag(0);
            mqRequestMsg.setBody(ObjectUtil.toByteArray(refundNotifyMsg));
            qcMsgClient.asyncSend(mqRequestMsg);
            flag=false;
        }
        if(!flag){
            OrderMq orderMq = new OrderMq();
            orderMq.setOrderno(refundNotifyMsg.getOrderNo());
            orderMq.setOutTradeNo(order.getOutTradeNo());
            orderMq.setType(OrderCallBackMsg.REFUND_SUBMIT);
            orderMq.setParam(orderNo);
            orderMq.setState(OrderCallBackMsg.FAIL);
            orderMq.setSystemCode(order.getSourceSystemId());
            int count=eOrderMqMapper.updateCheckTime(refundNotifyMsg.getOrderNo(),OrderCallBackMsg.REFUND_SUBMIT);
            if(count==0){
                try{
                    orderMqMapper.insertSelective(orderMq);
                }catch (Exception e){
                    eOrderMqMapper.updateCheckTime(refundNotifyMsg.getOrderNo(),OrderCallBackMsg.REFUND_SUBMIT);
                }
            }
        }
    }

    private void sendMessageToMQ(RefundNotifyMsg refundNotifyMsg) {
        Order order = this.orderService.selectOrderByOrderNo(null, refundNotifyMsg.getOrderNo());
        RefundRecord refundRecord=payService.selectByRefundOrderNo(refundNotifyMsg.getRefundOrderNo());
        List<RespRefundPayInfo> respRefundPayInfos = this.payService.selectRefundPayInfoList(refundNotifyMsg.getRefundOrderNo());
        refundNotifyMsg.setSystemCode(order.getSourceSystemId());
        refundNotifyMsg.setBusinessCode(order.getSourceBusinessId());
        refundNotifyMsg.setRefundPayInfos(respRefundPayInfos);
        refundNotifyMsg.setOutTradeNo(order.getOutTradeNo());
        refundNotifyMsg.setUid(order.getUid());
        refundNotifyMsg.setRefundTime(refundRecord.getRefundTime().getTime());
        refundNotifyMsg.setRefundRecvAccount(refundRecord.getRefundRecvAccount());
        boolean flag=true;
        Gson gson = new GsonBuilder().create();
        System.out.println(gson.toJson(refundNotifyMsg));

        String notifyUrl = refundRecord.getRefundNotifyUrl();
        if (!HttpUtils.isValidURL(notifyUrl)) {
            notifyUrl = order.getRefundNotifyUrl();
        }

        if (HttpUtils.isValidURL(notifyUrl)) {
            try {
                String result = HttpUtils.sendWebRequestByPostJsonStr(null, notifyUrl, gson.toJson(refundNotifyMsg));
                logger.warn("订单号：{}。退款成功回调通知业务系统。回调地址：{}。请求{}，晌应{}。", order.getOrderNo(), notifyUrl, GsonUtils.toJson(refundNotifyMsg), result);
                java.lang.reflect.Type type = new TypeToken<BackInfo>() {
                }.getType();
                BackInfo backInfo = gson.fromJson(result, type);
                if (null==backInfo||!(backInfo.getRet() && backInfo.getErrcode().equals(200))) {
                    flag = false;
                }else{
                    //通知业务系统成功
                    eOrderMqMapper.updateSuccess(order.getOrderNo(),OrderCallBackMsg.REFUND);
                }
            } catch (Exception e){
                return ;
            }
        } else {
            //废弃
            MqRequestMsg mqRequestMsg = new MqRequestMsg();
            mqRequestMsg.setTopic(OrderPayService.TOPIC_ORDER_REFUND_STATUS_NOTIFY); //退款通知.
            mqRequestMsg.setTag(order.getSourceSystemId());
            mqRequestMsg.setMsgId(refundNotifyMsg.getOrderNo()); //订单号.
            mqRequestMsg.setFlag(0);
            mqRequestMsg.setBody(ObjectUtil.toByteArray(refundNotifyMsg));
            qcMsgClient.asyncSend(mqRequestMsg);
            flag = false;
        }

        if(!flag){
            OrderMq orderMq = new OrderMq();
            orderMq.setOrderno(refundNotifyMsg.getOrderNo());
            orderMq.setOutTradeNo(order.getOutTradeNo());
            orderMq.setType(OrderCallBackMsg.REFUND);
            orderMq.setParam(gson.toJson(refundNotifyMsg));
            orderMq.setState(OrderCallBackMsg.FAIL);
            orderMq.setSystemCode(order.getSourceSystemId());
            int count=eOrderMqMapper.updateCheckTime(refundNotifyMsg.getOrderNo(),OrderCallBackMsg.REFUND);
            if(count==0){
                try{
                    orderMqMapper.insertSelective(orderMq);
                }catch (Exception e){
                    eOrderMqMapper.updateCheckTime(refundNotifyMsg.getOrderNo(),OrderCallBackMsg.REFUND);
                }
            }
        }
    }

    @Override
    public void callBackByWithdraw(WithdrawTransferNotify notifyDetail,String source) {
        boolean flag=true;
        Gson gson = new GsonBuilder().create();
        //防止第三方重复发送，重复发送给各个业务系统
        if(source.equals(OrderMqConstants.PAY_RESEND)){
            try {
                OrderMq orderMq = new OrderMq();
                orderMq.setOrderno(notifyDetail.getWithdrawNo());
                orderMq.setOutTradeNo(notifyDetail.getApplyNo());
                orderMq.setType(OrderCallBackMsg.WITHDRAW);
                orderMq.setSystemCode(notifyDetail.getSourceSystemCode());
                orderMq.setParam(gson.toJson(notifyDetail));
                orderMq.setState(OrderCallBackMsg.FAIL);
                orderMq.setSendAmount((byte)0);
                orderMqMapper.insertSelective(orderMq);
                //同步返回，不然异步会比同步调用快的
                return ;
            }catch (Exception e){
                logger.warn("第三方重复发送,提现号为："+notifyDetail.getWithdrawNo());
                return ;
            }
        }
        if (!StringUtil.isBlankOrNull(notifyDetail.getNotifyUrl()) && HttpUtils.isValidURL(notifyDetail.getNotifyUrl())) {
            try {
                String result = HttpUtils.sendWebRequestByPostJsonStr(null, notifyDetail.getNotifyUrl(), gson.toJson(notifyDetail));
                logger.warn("提现号：{}。提现成功回调通知业务系统。回调地址：{}。请求{}，晌应{}。", notifyDetail.getWithdrawNo(), notifyDetail.getNotifyUrl(), GsonUtils.toJson(notifyDetail), result);
                java.lang.reflect.Type type = new TypeToken<BackInfo>() {
                }.getType();
                BackInfo backInfo = gson.fromJson(result, type);
                if (null==backInfo||!(backInfo.getRet() && backInfo.getErrcode().equals(200))) {
                    flag = false;
                }else{
                    //通知业务系统成功
                    eOrderMqMapper.updateSuccess(notifyDetail.getWithdrawNo(),OrderCallBackMsg.WITHDRAW);
                }
            }catch (Exception e){
                return ;
            }

        } else {
            flag=false;
        }
        if(!flag){
            //失败完后更新重发次数和检验时间
            int count=eOrderMqMapper.updateCheckTime(notifyDetail.getWithdrawNo(),OrderCallBackMsg.WITHDRAW);
        }
    }

    private void sendMessageToMQClose(String orderNo){
        Order order = this.orderService.selectOrderByOrderNo(null, orderNo);
        OrderNotifyMsg orderNotifyMsg = new OrderNotifyMsg();
        orderNotifyMsg.setUid(order.getUid());
        orderNotifyMsg.setExtraParam(order.getExtraParam());
        orderNotifyMsg.setOrderAmount(order.getOrderAmount());
        orderNotifyMsg.setOrderNo(order.getOrderNo());
        orderNotifyMsg.setOutTradeNo(order.getOutTradeNo());
        orderNotifyMsg.setPayAmount(order.getPayAmount());
        orderNotifyMsg.setResultCode(OrderNotifyMsg.RESULT_CODE_ORDER_CLOSE_SUCCESS);
        orderNotifyMsg.setSourceSystemCode(order.getSourceSystemId());
        orderNotifyMsg.setSourceBusinessCode(order.getSourceBusinessId());

        List<PayRecordDetail> payRecordDetails = this.payService.selectPayRecordDetailByOrderNo(order.getOrderNo());

        List<ReqPayInfo> reqPayInfos = new ArrayList<>();
        ReqPayInfo reqPayInfo = null;
        for (PayRecordDetail payRecordDetail : payRecordDetails) {
            reqPayInfo = new ReqPayInfo();
            reqPayInfo.setPayId(payRecordDetail.getPayId());
            reqPayInfo.setAmount(payRecordDetail.getPayAmount());
            reqPayInfos.add(reqPayInfo);
        }
        orderNotifyMsg.setPayInfoList(reqPayInfos);
        //mq或回调成功
        boolean flag=true;
        Gson gson = new GsonBuilder().create();
        if (!StringUtil.isBlankOrNull(order.getCloseNotifyUrl()) && HttpUtils.isValidURL(order.getCloseNotifyUrl())) {
            try {
                logger.warn("订单号：" + orderNo + "。订单关闭回调:" + order.getCloseNotifyUrl() + "参数:" + gson.toJson(orderNotifyMsg));
                String result = HttpUtils.sendWebRequestByPostJsonStr(null, order.getCloseNotifyUrl(), gson.toJson(orderNotifyMsg));
                logger.warn("订单号：" + orderNo + "。订单关闭回调:" + order.getCloseNotifyUrl() + "结果:" + result);
                java.lang.reflect.Type type = new TypeToken<BackInfo>() {
                }.getType();
                BackInfo backInfo = gson.fromJson(result, type);
                if (null==backInfo||!(backInfo.getRet() && backInfo.getErrcode().equals(200))) {
                    flag = false;
                }else{
                    //通知业务系统成功
                    eOrderMqMapper.updateSuccess(orderNo,OrderCallBackMsg.CLOSE);
                }
            }catch (Exception e){
                return;
            }


        } else {
            MqRequestMsg mqRequestMsg = new MqRequestMsg();
            mqRequestMsg.setTopic(OrderPayService.TOPIC_ORDER_CLOSE_STATUS_NOTIFY);
            mqRequestMsg.setTag(order.getSourceSystemId());
            mqRequestMsg.setMsgId(orderNo); //订单号.
            mqRequestMsg.setFlag(0);
            mqRequestMsg.setBody(ObjectUtil.toByteArray(orderNotifyMsg));;
            qcMsgClient.asyncSend(mqRequestMsg);
            flag=false;
        }
        if(!flag){
            OrderMq orderMq=new OrderMq();
            orderMq.setOrderno(orderNo);
            orderMq.setOutTradeNo(order.getOutTradeNo());
            orderMq.setType(OrderCallBackMsg.CLOSE);
            orderMq.setSystemCode(order.getSourceSystemId());
            orderMq.setParam(orderNo);
            orderMq.setState(OrderCallBackMsg.FAIL);
            int count=eOrderMqMapper.updateCheckTime(orderNo,OrderCallBackMsg.CLOSE);
            if(count==0){
                try{
                    orderMqMapper.insertSelective(orderMq);
                }catch (Exception e){
                    eOrderMqMapper.updateCheckTime(orderNo,OrderCallBackMsg.CLOSE);
                }
            }

        }
    }

    private void callBackScanPay(PaySuccessData paySuccessData) {
        Order order = this.orderService.selectOrderByOrderNo(null, paySuccessData.getOrderNo());
        OrderNotifyMsg orderNotifyMsg = new OrderNotifyMsg();
        orderNotifyMsg.setUid(order.getUid());
        orderNotifyMsg.setExtraParam(order.getExtraParam());
        orderNotifyMsg.setOrderAmount(order.getOrderAmount());
        orderNotifyMsg.setOrderNo(order.getOrderNo());
        orderNotifyMsg.setOutTradeNo(order.getOutTradeNo());
        orderNotifyMsg.setPayAmount(order.getPayAmount());
        orderNotifyMsg.setPayTime(order.getPayTime().getTime());
        orderNotifyMsg.setRefundAmount(order.getRefundAmount());
        orderNotifyMsg.setResultCode(OrderNotifyMsg.RESULT_CODE_USER_PAY_SUCCESS);
        orderNotifyMsg.setSourceSystemCode(order.getSourceSystemId());
        orderNotifyMsg.setSourceBusinessCode(order.getSourceBusinessId());

        List<PayRecordDetail> payRecordDetails = this.payService.selectPayRecordDetailByOrderNo(order.getOrderNo());

        List<ReqPayInfo> reqPayInfos = new ArrayList<>();
        ReqPayInfo reqPayInfo = null;
        for (PayRecordDetail payRecordDetail : payRecordDetails) {
            reqPayInfo = new ReqPayInfo();
            reqPayInfo.setPayId(payRecordDetail.getPayId());
            reqPayInfo.setAmount(payRecordDetail.getPayAmount());
            reqPayInfos.add(reqPayInfo);
        }
        orderNotifyMsg.setPayInfoList(reqPayInfos);

        //mq或回调成功

        boolean flag = true;
        Gson gson = new GsonBuilder().create();
        //防止第三方重复发送，重复发送给各个业务系统
        if (paySuccessData.getSourceType().equals(OrderMqConstants.PAY_RESEND)) {
            try {
                OrderMq orderMq = new OrderMq();
                orderMq.setOrderno(paySuccessData.getOrderNo());
                orderMq.setOutTradeNo(order.getOutTradeNo());
                orderMq.setType(OrderCallBackMsg.SCAN_PAY);
                orderMq.setSystemCode(order.getSourceSystemId());
                orderMq.setParam(gson.toJson(paySuccessData));
                orderMq.setState(OrderCallBackMsg.FAIL);
                orderMq.setSendAmount((byte) 0);
                orderMqMapper.insertSelective(orderMq);
                //同步返回，不然异步会比同步调用快的
                return ;
            } catch (Exception e) {
                logger.warn("第三方重复发送:" + order.getOrderNo());
                return;
            }
        }
        if (!StringUtil.isBlankOrNull(order.getPayConfirmNotifyUrl()) && HttpUtils.isValidURL(order.getPayConfirmNotifyUrl())) {
            try {
                String result = HttpUtils.sendWebRequestByPostJsonStr(null, order.getPayConfirmNotifyUrl(), gson.toJson(orderNotifyMsg));
                logger.warn("订单号：{}。支付成功回调通知业务系统。回调地址：{}。请求{}，晌应{}。", order.getOrderNo(), order.getPayConfirmNotifyUrl(), GsonUtils.toJson(orderNotifyMsg), result);
                java.lang.reflect.Type type = new TypeToken<BackInfo>() {
                }.getType();
                BackInfo backInfo = gson.fromJson(result, type);
                if (null == backInfo || !(backInfo.getRet() && backInfo.getErrcode().equals(200))) {
                    flag = false;
                } else {
                    //通知业务系统成功
                    eOrderMqMapper.updateSuccess(paySuccessData.getOrderNo(), OrderCallBackMsg.SCAN_PAY);
                }
            } catch (Exception e) {
                return;
            }

        } else {
            //废弃
            MqRequestMsg mqRequestMsg = new MqRequestMsg();
            mqRequestMsg.setTopic(OrderPayService.TOPIC_ORDER_STATUS_NOTIFY);
            mqRequestMsg.setTag(order.getSourceSystemId());
            mqRequestMsg.setMsgId(paySuccessData.getOrderNo()); //订单号.
            mqRequestMsg.setFlag(0);
            mqRequestMsg.setBody(ObjectUtil.toByteArray(orderNotifyMsg));
            ;
            qcMsgClient.asyncSend(mqRequestMsg);
            flag = false;
        }
        if (!flag) {
            //失败完后更新重发次数和检验时间
            int count = eOrderMqMapper.updateCheckTimeScanPay(paySuccessData.getOrderNo(), OrderCallBackMsg.SCAN_PAY);
            if (count == 0) {
                try {
                    OrderMq orderMq = new OrderMq();
                    orderMq.setOrderno(paySuccessData.getOrderNo());
                    orderMq.setOutTradeNo(order.getOutTradeNo());
                    orderMq.setType(OrderCallBackMsg.SCAN_PAY);
                    orderMq.setSystemCode(order.getSourceSystemId());
                    orderMq.setParam(gson.toJson(paySuccessData));
                    orderMq.setState(OrderCallBackMsg.FAIL);
                    orderMqMapper.insertSelective(orderMq);
                } catch (Exception e) {
                    eOrderMqMapper.updateCheckTimeScanPay(paySuccessData.getOrderNo(), OrderCallBackMsg.SCAN_PAY);
                }
            }

        }
    }

    private void sendMessageToMQ(PaySuccessData paySuccessData) {
        Order order = this.orderService.selectOrderByOrderNo(null, paySuccessData.getOrderNo());
        OrderNotifyMsg orderNotifyMsg = new OrderNotifyMsg();
        orderNotifyMsg.setUid(order.getUid());
        orderNotifyMsg.setExtraParam(order.getExtraParam());
        orderNotifyMsg.setOrderAmount(order.getOrderAmount());
        orderNotifyMsg.setOrderNo(order.getOrderNo());
        orderNotifyMsg.setOutTradeNo(order.getOutTradeNo());
        orderNotifyMsg.setPayAmount(order.getPayAmount());
        orderNotifyMsg.setPayTime(order.getPayTime().getTime());
        orderNotifyMsg.setRefundAmount(order.getRefundAmount());
        orderNotifyMsg.setResultCode(OrderNotifyMsg.RESULT_CODE_USER_PAY_SUCCESS);
        orderNotifyMsg.setSourceSystemCode(order.getSourceSystemId());
        orderNotifyMsg.setSourceBusinessCode(order.getSourceBusinessId());
        orderNotifyMsg.setBuyerBank(paySuccessData.getBuyerBank());
        List<PayRecordDetail> payRecordDetails = this.payService.selectPayRecordDetailByOrderNo(order.getOrderNo());

        List<ReqPayInfo> reqPayInfos = new ArrayList<>();
        ReqPayInfo reqPayInfo = null;
        for (PayRecordDetail payRecordDetail : payRecordDetails) {
            reqPayInfo = new ReqPayInfo();
            reqPayInfo.setPayId(payRecordDetail.getPayId());
            reqPayInfo.setAmount(payRecordDetail.getPayAmount());
            reqPayInfos.add(reqPayInfo);
        }
        orderNotifyMsg.setPayInfoList(reqPayInfos);
        //mq或回调成功
        boolean flag=true;
        Gson gson = new GsonBuilder().create();
        //防止第三方重复发送，重复发送给各个业务系统
        if(paySuccessData.getSourceType().equals(OrderMqConstants.PAY_RESEND)){
            try {
                OrderMq orderMq = new OrderMq();
                orderMq.setOrderno(paySuccessData.getOrderNo());
                orderMq.setOutTradeNo(order.getOutTradeNo());
                orderMq.setType(OrderCallBackMsg.PAY);
                orderMq.setSystemCode(order.getSourceSystemId());
                orderMq.setParam(gson.toJson(paySuccessData));
                orderMq.setState(OrderCallBackMsg.FAIL);
                orderMq.setSendAmount((byte)0);
                orderMqMapper.insertSelective(orderMq);
            }catch (Exception e){
                logger.warn("第三方重复发送:"+order.getOrderNo());
                return ;
            }
        }
        if (!StringUtil.isBlankOrNull(order.getNotifyUrl()) && HttpUtils.isValidURL(order.getNotifyUrl())) {
            try {
                String result = HttpUtils.sendWebRequestByPostJsonStr(null, order.getNotifyUrl(), gson.toJson(orderNotifyMsg));
                logger.warn("订单号：{}。支付成功回调通知业务系统。回调地址：{}。请求{}，晌应{}。", order.getOrderNo(), order.getNotifyUrl(), GsonUtils.toJson(orderNotifyMsg), result);
                java.lang.reflect.Type type = new TypeToken<BackInfo>() {
                }.getType();
                BackInfo backInfo = gson.fromJson(result, type);
                if (null==backInfo||!(backInfo.getRet() && backInfo.getErrcode().equals(200))) {
                    flag = false;
                }else{
                    //通知业务系统成功
                    eOrderMqMapper.updateSuccess(paySuccessData.getOrderNo(),OrderCallBackMsg.PAY);
                }
            }catch (Exception e){
                return ;
            }

        } else {
            //废弃
            MqRequestMsg mqRequestMsg = new MqRequestMsg();
            mqRequestMsg.setTopic(OrderPayService.TOPIC_ORDER_STATUS_NOTIFY);
            mqRequestMsg.setTag(order.getSourceSystemId());
            mqRequestMsg.setMsgId(paySuccessData.getOrderNo()); //订单号.
            mqRequestMsg.setFlag(0);
            mqRequestMsg.setBody(ObjectUtil.toByteArray(orderNotifyMsg));;
            qcMsgClient.asyncSend(mqRequestMsg);
            flag=false;
        }
        if(!flag){
            //失败完后更新重发次数和检验时间
            int count=eOrderMqMapper.updateCheckTime(paySuccessData.getOrderNo(),OrderCallBackMsg.PAY);
            if(count==0){
                try{
                    OrderMq orderMq=new OrderMq();
                    orderMq.setOrderno(paySuccessData.getOrderNo());
                    orderMq.setOutTradeNo(order.getOutTradeNo());
                    orderMq.setType(OrderCallBackMsg.PAY);
                    orderMq.setSystemCode(order.getSourceSystemId());
                    orderMq.setParam(gson.toJson(paySuccessData));
                    orderMq.setState(OrderCallBackMsg.FAIL);
                    orderMqMapper.insertSelective(orderMq);
                }catch (Exception e){
                    eOrderMqMapper.updateCheckTime(paySuccessData.getOrderNo(),OrderCallBackMsg.PAY);
                }
            }

        }


    }

    /**
     * 提现付款，支付宝回调处理
     */
    @Override
    @Transactional
    public boolean withdrawCompleteProccess(AliPayBatchTransNotifyData notifyData) {
        SimpleDateFormat sdf1 = new SimpleDateFormat("yyyyMMddhhmmss");
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String batchNo = notifyData.getBatch_no();
        String notifyId = notifyData.getNotify_id();

        //1. 记录到tb_tsn_record，第三方返回的数据记录下来
        TSNRecord tsnRecord = new TSNRecord();
        tsnRecord.setPayId(PayWayEnum.PAY_WAY_ALIPAY.getPayId());
        tsnRecord.setDataType("JSON");
        tsnRecord.setRespDate(JSON.toJSONString(notifyData));
        tsnRecord.setTsn(notifyId);
        tsnRecord.setTsnType("Withdraw");
        tsnRecord.setOrderNo(batchNo);
        tsnRecord.setStatus((byte) 2);//处理成功
        tsnRecordMapper.insert(tsnRecord);

        //2. 更新提现记录表
//        WithdrawRecordExample withdrawRecordExample = new WithdrawRecordExample();
//        withdrawRecordExample.createCriteria().andBatchNoEqualTo(batchNo);
//        WithdrawRecord withdrawRecord = new WithdrawRecord();
//        withdrawRecord.setStatus(batchStatus);
//        withdrawRecord.setNotifyTime(new Date());
//        withdrawRecordMapper.updateByExampleSelective(withdrawRecord, withdrawRecordExample);
        WithdrawBatchExample withdrawBatchExample = new WithdrawBatchExample();
        withdrawBatchExample.createCriteria().andBatchNoEqualTo(batchNo).andStatusNotEqualTo((byte)3);
        WithdrawBatch withdrawBatch = new WithdrawBatch();
        withdrawBatch.setStatus((byte)2);
        withdrawBatch.setNotifyTime(new Date());
        int count = withdrawBatchMapper.updateByExampleSelective(withdrawBatch,withdrawBatchExample);
        //真正向第三方付款
        if(count != 0){
            //成功和失败的转账记录
            List<WithdrawTransferNotify> successDetails = convert2NotifyObject(batchNo, notifyData.getSuccess_details());
            List<WithdrawTransferNotify> failDetails = convert2NotifyObject(batchNo, notifyData.getFail_details());
            logger.info("success size:{}, fail size:{}", successDetails.size(), failDetails.size());

            List<WithdrawTransferNotify> notifyDetails = new ArrayList<>();
            //3. 更新提现申请表
            for (WithdrawTransferNotify Snotify : successDetails) {
                notifyDetails.add(Snotify);
                WithdrawApply record = new WithdrawApply();
                record.setWithdrawNo(Integer.valueOf(Snotify.getWithdrawNo()));
                record.setStatus((byte) 2); //提现转账成功
                record.setAuditStatus((byte) 1);
                record.setTsnNo(Snotify.getTsn());  //支付宝内部处理流水号
                record.setResult("付款成功");
                record.setPayAmount(Snotify.getAmount()); //更新实际付款金额
                try{
                    record.setDealTime(simpleDateFormat.parse(simpleDateFormat.format(sdf1.parse(Snotify.getCompletedTime()))));
                }catch (Exception e){
                    logger.info("转换提现完成时间异常:"+Snotify.getCompletedTime());
                }

                withdrawApplyMapper.updateByPrimaryKeySelective(record);
            }
            for (WithdrawTransferNotify Fnotify : failDetails) {
                notifyDetails.add(Fnotify);
                WithdrawApply record = new WithdrawApply();
                record.setWithdrawNo(Integer.valueOf(Fnotify.getWithdrawNo()));
                String freason = Fnotify.getReason();
                record.setResult(freason);
                if (isInnerReason(freason)){
                    record.setStatus((byte) 3); //内部原因，提现转账失败
                    try{
                        record.setDealTime(simpleDateFormat.parse(simpleDateFormat.format(sdf1.parse(Fnotify.getCompletedTime()))));
                    }catch (Exception e){
                        logger.info("转换提现完成时间异常:"+Fnotify.getCompletedTime());
                    }
                    record.setResult(getReasonByCode(freason));
                }else {
                    record.setStatus((byte) 4); //外部原因，提现转账失败
                }
                record.setAuditStatus((byte) 1);
                record.setTsnNo(Fnotify.getTsn());  //支付宝内部处理流水号
                withdrawApplyMapper.updateByPrimaryKeySelective(record);
            }


            //4. 发送MQ消息给业务系统，通知
            for (WithdrawTransferNotify notifyDetail : notifyDetails) {
                String freason = notifyDetail.getReason(); //可以重新发起付款，暂时不发mq通知
                if (isInnerReason(freason)){
                    logger.warn(freason + "，可以重新发起付款，暂时不发回调通知");
                    continue;
                }

                //优先使用notify_url
                WithdrawApply apply = withdrawApplyMapper.selectByPrimaryKey(Integer.valueOf(notifyDetail.getWithdrawNo()));
                notifyDetail.setNotifyUrl(apply.getNotifyUrl());
                callBackByWithdraw(notifyDetail,OrderMqConstants.PAY_RESEND);
            }
        }


        return true;
    }

    private boolean isInnerReason(String code){
        if ("DAILY_QUOTA_LIMIT_EXCEED".equals(code)
                || "TRANSFER_AMOUNT_NOT_ENOUGH".equals(code) || "PERMIT_PAYER_L1_FORBIDDEN".equals(code)
                || "PERMIT_CHECK_PERM_AML_CERT_EXPIRED".equals(code) || "PERMIT_PAYER_L2_L3_FORBIDDEN".equals(code) || "PERMIT_CHECK_PERM_AML_DATA_INCOMPLETE".equals(code)
                || "PERMIT_CHECK_PERM_AML_CERT_MISS_4_TRANS_LIMIT".equals(code)
                || "批次超时未处理强制作废！".equals(code)){
            return true;
        }
        return false;
    }

    private String getReasonByCode(String code){
        if (StringUtil.isBlankOrNull(code)){
            return "";
        }
        if ("DAILY_QUOTA_LIMIT_EXCEED".equals(code)){
            return "日限额超限";
        }
        if ("TRANSFER_AMOUNT_NOT_ENOUGH".equals(code)){
            return "转账余额不足，批次失败";
        }
        if ("ERROR_OTHER_CERTIFY_LEVEL_LIMIT".equals(code)){
            return "收款账户实名认证信息不完整，无法收款";
        }
        if ("PERMIT_PAYER_L1_FORBIDDEN".equals(code)){
            return "根据监管部门的要求，当前余额支付额度仅剩XX元，请尽快完善身份信息提升额度";
        }
        if ("PERMIT_PAYER_L2_L3_FORBIDDEN".equals(code)){
            return "根据监管部门的要求，您今日余额支付额度仅剩XX元，今年余额支付额度仅剩XX元";
        }
        if ("PERMIT_CHECK_PERM_AML_DATA_INCOMPLETE".equals(code)){
            return "由于您的资料不全，付款受限";
        }
        if ("PERMIT_CHECK_PERM_AML_CERT_EXPIRED".equals(code)){
            return "由于您的证件过期，付款受限";
        }
        if ("PERMIT_CHECK_PERM_AML_CERT_MISS_4_TRANS_LIMIT".equals(code)){
            return "您的账户收付款额度超限";
        }
        return code;
    }

    @Override
    public void orderMqResend(){
        OrderMqExample orderMqExample=new OrderMqExample();
        orderMqExample.createCriteria().andCheckTimeLessThanOrEqualTo(new Date()).andStateEqualTo(OrderCallBackMsg.FAIL).andSendAmountLessThan((byte)8)
                .andTypeNotEqualTo(OrderCallBackMsg.SCAN_PAY.byteValue());
        List<OrderMq> orderMqList=orderMqMapper.selectByExample(orderMqExample);
        Gson gson = new GsonBuilder().create();
        for(OrderMq orderMq:orderMqList){
            if(orderMq.getType().equals(OrderCallBackMsg.PAY)){
                Type paySuccessDataType = new TypeToken<PaySuccessData>(){}.getType();
                PaySuccessData paySuccessData=gson.fromJson(orderMq.getParam(), paySuccessDataType);
                paySuccessData.setSourceType(OrderMqConstants.TASK_RESEND);
                sendMessageToMQ(paySuccessData);
            }else if(orderMq.getType().equals(OrderCallBackMsg.REFUND)){
                Type refundNotifyMsgType = new TypeToken<RefundNotifyMsg>(){}.getType();
                RefundNotifyMsg refundNotifyMsg=gson.fromJson(orderMq.getParam(),refundNotifyMsgType);
                sendMessageToMQ(refundNotifyMsg);
            }else if(orderMq.getType().equals(OrderCallBackMsg.CLOSE)){
                sendMessageToMQClose(orderMq.getParam());
            }else if(orderMq.getType().equals(OrderCallBackMsg.REFUND_SUBMIT)){
                sendMessageToMQrefundApply(orderMq.getParam());
            } else if (orderMq.getType().equals(OrderCallBackMsg.REFUND_EGGS)) {
                sendRefundEggsRequest(orderMq);
            } else if (orderMq.getType().equals(OrderCallBackMsg.WITHDRAW)) {
                Type withdrawTransferNotifyType = new TypeToken<WithdrawTransferNotify>(){}.getType();
                WithdrawTransferNotify withdrawTransferNotify=gson.fromJson(orderMq.getParam(), withdrawTransferNotifyType);
                callBackByWithdraw(withdrawTransferNotify,OrderMqConstants.TASK_RESEND);
            }
        }


    }

    @Override
    public void callBackSacnPayResend(){
        OrderMqExample orderMqExample=new OrderMqExample();
        orderMqExample.createCriteria().andCheckTimeLessThanOrEqualTo(new Date()).andStateEqualTo(OrderCallBackMsg.FAIL).andSendAmountLessThan((byte)8)
                .andTypeEqualTo(OrderCallBackMsg.SCAN_PAY.byteValue());
        List<OrderMq> orderMqList=orderMqMapper.selectByExample(orderMqExample);
        Gson gson = new GsonBuilder().create();
        for(OrderMq orderMq:orderMqList){
            Type paySuccessDataType = new TypeToken<PaySuccessData>(){}.getType();
            PaySuccessData paySuccessData=gson.fromJson(orderMq.getParam(), paySuccessDataType);
            paySuccessData.setSourceType(OrderMqConstants.TASK_RESEND);
            callBackScanPay(paySuccessData);
        }


    }


    @Override
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public void withdrawReset() {
        WithdrawBatchExample withdrawBatchExample = new WithdrawBatchExample();
        WithdrawBatchExample.Criteria criteria = withdrawBatchExample.createCriteria();
        criteria.andStatusEqualTo((byte)1);
        criteria.andUpdateTimeLessThanOrEqualTo(DateUtils.addTime(new Date(), -6, DateUtils.TIME_TYPE_HOUR));
        List<WithdrawBatch> withdrawBatchList = withdrawBatchMapper.selectByExample(withdrawBatchExample);
        for(WithdrawBatch withdrawBatch : withdrawBatchList){
            //支付宝扫描枪订单查询
            AlipayConfig alipayConfig = payConfigService.getAlipayConfig("2", 1);
            APIResponse apiResponse=alipayComponent.btnStatusQuery(withdrawBatch.getBatchNo(),alipayConfig);
            if(apiResponse.isRet()&&null!=apiResponse.getData()&&("W").equals(apiResponse.getData())){
                //未输入密码6个小时后重置
                logger.info("批次号"+withdrawBatch.getBatchNo()+"在6个小时未输入密码状态重置");
                WithdrawBatchExample updateWithdrawBatchExample = new WithdrawBatchExample();
                updateWithdrawBatchExample.createCriteria().andBatchNoEqualTo(withdrawBatch.getBatchNo())
                    .andStatusEqualTo((byte)1);
                WithdrawBatch updateWithdrawBatch = new WithdrawBatch();
                updateWithdrawBatch.setStatus((byte)3);
                withdrawBatchMapper.updateByExampleSelective(updateWithdrawBatch,updateWithdrawBatchExample);
                //获取该批次的流水记录
                logger.info("提现流水号："+withdrawBatch.getWithdrawNos());
                List<String> withdrawNoListt = Arrays.asList(withdrawBatch.getWithdrawNos().split(","));
                int updateApplyCount = eWithdrawApplyMapper.updateApplyByWithdrawNos(withdrawNoListt);
//                String[] strlist = withdrawBatchList.get(0).getWithdrawNos().split(",");
//                List<Integer> withdrawNoList = new ArrayList<Integer>();
//                for(String str : strlist) {
//                    withdrawNoList.add(Integer.parseInt(str));
//                }
//                WithdrawApplyExample withdrawApplyExample = new WithdrawApplyExample();
//                withdrawApplyExample.createCriteria().andWithdrawNoIn(withdrawNoList);
//                WithdrawApply withdrawApply = new WithdrawApply();
//                withdrawApply.setStatus((byte)0);
//                int updateApplyCount = withdrawApplyMapper.updateByExampleSelective(withdrawApply,withdrawApplyExample);
                logger.info("更新提现申请表数："+updateApplyCount);
            }else if(!apiResponse.isRet()&&("NO_RECORD").equals(apiResponse.getErrmsg())){
                logger.info("批次号"+withdrawBatch.getBatchNo()+"查询信息为空");
                WithdrawBatchExample updateWithdrawBatchExample = new WithdrawBatchExample();
                updateWithdrawBatchExample.createCriteria().andBatchNoEqualTo(withdrawBatch.getBatchNo())
                        .andStatusEqualTo((byte)1);
                WithdrawBatch updateWithdrawBatch = new WithdrawBatch();
                updateWithdrawBatch.setStatus((byte)4);
                withdrawBatchMapper.updateByExampleSelective(updateWithdrawBatch,updateWithdrawBatchExample);
                //获取该批次的流水记录
                logger.info("提现流水号："+withdrawBatch.getWithdrawNos());
                List<String> withdrawNoListt = Arrays.asList(withdrawBatch.getWithdrawNos().split(","));
                int updateApplyCount = eWithdrawApplyMapper.updateApplyByWithdrawNos(withdrawNoListt);
                logger.info("更新提现申请表数："+updateApplyCount);
            }
        }
    }
    private void sendRefundEggsRequest(OrderMq orderMq) {
//        ReqAccumulateRefund reqRefund = GsonUtils.jsonStrToEntity(orderMq.getParam(), ReqAccumulateRefund.class);
//        APIRequest<ReqAccumulateRefund> request = new APIRequest<ReqAccumulateRefund>();
//        request.setData(reqRefund);
//        APIResponse<List<TbUserAssets>> response = userAssetsService.refundAccumulateSubmit(request);
//        if (response.isRet()) { // 鸟蛋退款成功
//            logger.info("重发鸟蛋退款成功。请求{}，晌应{}", GsonUtils.toJson(request), GsonUtils.toJson(response));
//            eOrderMqMapper.updateSuccess(orderMq.getOrderno(), OrderCallBackMsg.REFUND_EGGS);
//        } else { // 退款失败
//            eOrderMqMapper.updateCheckTime(orderMq.getOrderno(), OrderCallBackMsg.REFUND_EGGS);
//            logger.info("重发鸟蛋退款失败。请求{}，晌应{}", GsonUtils.toJson(request), GsonUtils.toJson(response));
//        }
    }

    private List<WithdrawTransferNotify> convert2NotifyObject(String batchNo, String formatStr) {
        List<WithdrawTransferNotify> notifyList = new ArrayList<>();
        if (StringUtil.isBlankOrNull(formatStr)) {
            return notifyList;
        }
        StringTokenizer tk = new StringTokenizer(formatStr, "|");
        while (tk.hasMoreTokens()) {
            String nextToken = tk.nextToken();
            String[] bee = nextToken.split("\\^");
            WithdrawTransferNotify notify = new WithdrawTransferNotify();
            notify.setBatchNo(batchNo);
            Integer withdrawNo = Integer.valueOf(bee[0]);
            WithdrawApply withdrawApply = withdrawApplyMapper.selectByPrimaryKey(withdrawNo);
            if (withdrawApply == null) {
                continue;
            }
            notify.setSourceSystemCode(withdrawApply.getSourceSystemCode());
            notify.setSourceBusinessCode(withdrawApply.getSourceBusinessCode());
            notify.setWithdrawNo(bee[0]);
            notify.setApplyNo(withdrawApply.getWithdrawApplyNo());
            notify.setAccountNo(bee[1]);
            notify.setName(bee[2]);
            BigDecimal amount = new BigDecimal(Double.valueOf(bee[3]));
            notify.setAmount(amount); //支付宝返回的单位是元
            String tag = bee[4];
            if ("S".equals(tag)) {
                notify.setTag(true);
            }
            if ("F".equals(tag)) {
                notify.setTag(false);
            }
            String reason = bee[5];
            if (!"null".equals(reason) || !StringUtil.isBlankOrNull(reason)) {
                notify.setReason(reason);
            }
            notify.setTsn(bee[6]);
            notify.setCompletedTime(bee[7]);
            notifyList.add(notify);
        }
        return notifyList;
    }

    @Override
    public void closeTimeOutOrder() {
        try {
            int pageNum = 1;
            int pageSize = 50;
            List<TimeoutOrderVo> list = new ArrayList<TimeoutOrderVo>();
            do {
                list = uOrderMapper.findTimeoutOrderVo((pageNum-1)*pageSize,pageSize);
                pageNum++;
                for (int i=0; i<list.size(); i++) {
                    TimeoutOrderVo vo = list.get(i);
                    processTimeoutOrderNo(vo);
                }
            } while (list.size()>0);
        } catch (Exception e) {
            logger.error("定时任务关闭订单出错", e);
        }
    }



    /**
     * 关闭超时订单
     * @param vo
     */
    private void processTimeoutOrderNo(TimeoutOrderVo vo) {
        WeichatServiceApi weichatServiceApi = new WeichatServiceApi();
        Integer payId = vo.getPayId();
        Integer orderId = vo.getOrderId();
        String mchId = vo.getMchId();
        String orderNo = vo.getOrderNo();
        if (payId == null || StringUtil.isBlankOrNull(mchId)) {
            return;
        }
        AccountPayRelation accountPayRelation = accountPayRelationService.getAccountPayRelation(vo.getMchId(), payId);
        if (accountPayRelation == null) {
            return;
        }
        if (payId.equals(PayWayEnum.PAY_WAY_WEICHAT.getPayId()) || payId.equals(PayWayEnum.PAY_WAY_WEICHATH5.getPayId())
                || payId.equals(PayWayEnum.PAY_WAY_WEICHAT_APPLET.getPayId())
                || payId.equals(PayWayEnum.PAY_WAY_WEICHAT_SCAN_CODE.getPayId())) { // 微信
            Configure configure = weichatAccountService.getWeichatConfigure(accountPayRelation.gettAId(), false);
            CloseOrdeReqData params = new CloseOrdeReqData();
            params.setAppid(configure.getAppID());
            params.setMch_id(configure.getMchID());
            params.setOut_trade_no(vo.getOrderNo());
            params.setNonce_str(StringUtil.genRandomCode(32, false));
            String sign = null;
            try {
                sign = Signature.getSign(params, configure.getKey());
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }

            params.setSign(sign);
            Map<String, String> resultMap = weichatServiceApi.closeOrder(params);
            if (resultMap == null) { // 微信返回为空的情况
                logger.info("关闭超时订单失败。单号：{}，请求参数：{}。返回参数：{}", orderNo, GsonUtils.toJson(params), resultMap);
                return;
            }
            String returnCode = resultMap.get("return_code");
            String resultCode = resultMap.get("result_code");
            String errCode = resultMap.get("err_code");
            if ("SUCCESS".equals(returnCode) && "SUCCESS".equals(resultCode)) { // 关闭订单成功
                boolean flag=orderService.closeOrder(orderId);
                if(flag){
                    this.sendMessageToMQClose(orderNo);
                    Order order=orderService.selectOrderByOrderNo(null,orderNo);
                    unfrezenUserAssest(order, "FAIL");
                }
                logger.info("成功关闭微信超时订单：{}", vo.getOrderNo());
            } else if ("SUCCESS".equals(returnCode) && "FAIL".equals(resultCode) && "ORDERPAID".equals(errCode)) { // 订单已支付
                orderService.updateOrderStatus(orderId, OrderStatusEnum.ORDER_STATE_CHECKED);
                logger.info("微信超时订单：{}。实际已支付，支付状态更改为已确定状态。请求参数：{}。返回参数：{}", orderNo, GsonUtils.toJson(params), resultMap);
            } else { // 关闭订单失败
                logger.info("关闭超时订单失败。单号：{}，请求参数：{}。返回参数：{}", orderNo, GsonUtils.toJson(params), resultMap);
            }
        } else if (payId.equals(PayWayEnum.PAY_WAY_ALIPAY.getPayId()) || PayWayEnum.PAY_WAY_ALIPAY_H5.getPayId().equals(payId)) { // 支付宝APP t和 支付宝H5支付
            AlipayConfig alipayConfig = payConfigService.getAlipayConfig(vo.getMchId(), vo.getPayId());
            AliRespQueryTrade aliRespQueryTrade = alipayComponent.queryTrade(orderNo, alipayConfig);
            if (canClose(aliRespQueryTrade)) {
                // 不需要向支付宝发送请求关闭订单
                boolean flag=orderService.closeOrder(orderId);
                if(flag) {
                    this.sendMessageToMQClose(orderNo);
                    Order order=orderService.selectOrderByOrderNo(null,orderNo);
                    unfrezenUserAssest(order, "FAIL");
                }
                logger.info("成功关闭支付宝超时订单：{}", orderNo);
            } else if ("T".equals(aliRespQueryTrade.getIs_success()) && "TRADE_SUCCESS".equals(aliRespQueryTrade.getResponse().get(0).getTrade_status())) {
                orderService.updateOrderStatus(orderId, OrderStatusEnum.ORDER_STATE_CHECKED);
                logger.info("支付宝超时订单：{}。实际已支付，支付状态更改为已确定状态。返回参数：{}", orderNo, GsonUtils.toJson(aliRespQueryTrade));
            } else {
                logger.error("关闭支付宝超时订单失败。单号：{}，返回参数{}", orderNo, GsonUtils.toJson(aliRespQueryTrade));
            }
        }else if(payId.equals(PayWayEnum.PAY_WAY_WEICHAT_SCAN.getPayId()) || payId.equals(PayWayEnum.PAY_WAY_WEICHAT_SCAN_CODE.getPayId())){
            Configure configure = weichatAccountService.getWeichatConfigure(accountPayRelation.gettAId(), false);
            CloseOrdeReqData params = new CloseOrdeReqData();
            params.setAppid(configure.getAppID());
            params.setMch_id(configure.getMchID());
            params.setOut_trade_no(vo.getOrderNo());
            params.setNonce_str(StringUtil.genRandomCode(32, false));
            String sign = null;
            try {
                sign = Signature.getSign(params, configure.getKey());
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }

            params.setSign(sign);
            Map<String, String> resultMap = weichatServiceApi.closeScanOrder(params);
            if (resultMap == null) { // 微信返回为空的情况
                logger.info("关闭超时订单失败。单号：{}，请求参数：{}。返回参数：{}", orderNo, GsonUtils.toJson(params), resultMap);
                return;
            }
            String returnCode = resultMap.get("return_code");
            String resultCode = resultMap.get("result_code");
            if ("SUCCESS".equals(returnCode) && "SUCCESS".equals(resultCode)) { // 关闭订单成功
                boolean flag = orderService.closeOrder(orderId);
                if (flag) {
                    this.sendMessageToMQClose(orderNo);
                    Order order = orderService.selectOrderByOrderNo(null, orderNo);
                    unfrezenUserAssest(order, "FAIL");
                }
                logger.info("成功关闭微信超时订单：{}", vo.getOrderNo());
            }
        }else if(payId.equals(PayWayEnum.PAY_WAY_ALIPAY_SCAN.getPayId())){
            //支付宝扫描枪订单查询
            AlipayConfig alipayConfig = payConfigService.getAlipayConfig(vo.getMchId(), vo.getPayId());
            AliPayTradeCloseReq aliPayTradeCloseReq = new AliPayTradeCloseReq();
            aliPayTradeCloseReq.setOut_trade_no(vo.getOrderNo());
            // APIResponse<AliPayTradeQueryResp> apiResponse=alipayComponent.tradeQuery(aliPayTradeQuery,alipayConfig);
            APIResponse<AliPayTradeCloseResp> apiResponse=alipayComponent.tradeClose(aliPayTradeCloseReq,alipayConfig);
            if(apiResponse.isRet()||(!apiResponse.isRet()&&("交易不存在").equals(apiResponse.getErrmsg()))){
                // 不需要向支付宝发送请求关闭订单
                boolean flag=orderService.closeOrder(orderId);
                if(flag) {
                    this.sendMessageToMQClose(orderNo);
                    Order order=orderService.selectOrderByOrderNo(null,orderNo);
                    unfrezenUserAssest(order, "FAIL");
                }
                logger.info("成功关闭支付宝扫描枪超时订单：{}", orderNo);
            }
        }
    }

    private void unfreezeCoupon(String orderNo, String result) {
        Order order=orderService.selectOrderByOrderNo(null,orderNo);
        //判断用户是否使用鸟蛋.
        List<PayRecordDetail> list = this.payService.selectPayRecordDetailByOrderNo(order.getOrderNo());

        for (PayRecordDetail payRecordDetail : list) {
            if (payRecordDetail.getPayId().equals(PayWayEnum.PAY_WAY_FOR_COUPON.getPayId()) ) {
                APIRequest<ReqCoupon> apiRequest=new APIRequest<ReqCoupon>();
                ReqCoupon reqCoupon=new ReqCoupon();
                reqCoupon.setSystemCode(order.getSourceSystemId());
                reqCoupon.setOrderNo(order.getOutTradeNo());
                apiRequest.setData(reqCoupon);
                if(result.equals("SUCCESS")){
                    //支付成功
                    couponService.unfreezeCouponSuccess(apiRequest);
                    logger.info("订单 {} 支付成功后解冻卡券!", order.getOrderNo() );
                    //补偿机制
                }else if(result.equals("FAIL")){
                    //超时未支付
                    couponService.unfreezeCouponFail(apiRequest);
                    logger.info("订单 {} 超时未支付后解冻卡券!", order.getOrderNo() );
                    //补偿机制
                }
                return;
            }
        }

    }

    private boolean canClose(AliRespQueryTrade aliRespQueryTrade) {
        if ("F".equals(aliRespQueryTrade.getIs_success()) && "TRADE_NOT_EXIST".equals(aliRespQueryTrade.getError())) {
            return true;
        }
        if ("T".equals(aliRespQueryTrade.getIs_success())) {
            String tradeStatus = aliRespQueryTrade.getResponse().get(0).getTrade_status();
            switch (tradeStatus) {
                case "TRADE_CLOSED"://交易中途关闭（已结束，未成功完成）
                    return true;
                case "WAIT_BUYER_PAY"://等待买家付款
                    return true;
                case "TRADE_REFUSE"://立即支付交易拒绝
                    return true;
                case "TRADE_REFUSE_DEALING"://立即支付交易拒绝中
                    return true;
                case "TRADE_CANCEL"://立即支付交易取消
                    return true;
            }
        }
        return false;
    }


    /**
     * 微信企业付款，从指定商户付款给用户
     */
    @Override
    public void transferFundByWechat(WithdrawPayInfo payInfo) {
        String openid = payInfo.getAccountNo();     //商户appid下，某用户的openid
        String withdrawNo = payInfo.getWithdrawNo();    //支付系统申请提现流水号
        BigDecimal amount = payInfo.getAmount().multiply(new BigDecimal(100));      //提现申请金额，单位为分，变为元
        BigDecimal payAmount = payInfo.getPayAmount().multiply(new BigDecimal(100)); //企业付款实际打款金额，单位为元
        String desc = null;
        if(null==payInfo.getWithdrawDesc()){
            desc = "提现";
        }else{
            desc = payInfo.getWithdrawDesc();
        }
        if (StringUtil.isBlankOrNull(openid) || StringUtil.isBlankOrNull(withdrawNo)
                || payAmount == null || (payAmount.doubleValue() <= 0) || StringUtil.isBlankOrNull(desc)) {
            logger.info("缺少必要参数");
            return ;
        }
        if (!NumberUtils.isDigits(withdrawNo)) {
            logger.info("非法提现号:"+withdrawNo);
            return ;
        }
        //判断此提现申请是否存在
        WithdrawApply apply = withdrawApplyMapper.selectByPrimaryKey(Integer.valueOf(withdrawNo));
        if (apply == null) {
            logger.info("支付系统未检查到提现申请号为[" + withdrawNo + "]的提现申请记录");
        } else {
            //如果已经付款成功了，不能再次提现，防止一此提现申请被重复提现多次
            if (apply.getStatus() == 2) {
                logger.info("支付系统检查到提现申请号为["+withdrawNo+"]的提现申请，系统已经付款");
            }
        }
        //状态变为第三方处理中
        Boolean isAllowWithdraw = updateWithdrawApplyByWeChat(Integer.valueOf(payInfo.getWithdrawNo()));
        if(!isAllowWithdraw){
            return ;
        }
        //获取公司的微信商户账户信息
        Integer accountVersion = apply.getAppVersion();
     //   APIResponse<WeichatAccount> accountResp = payService.getWeichatAccount(accountVersion==null?"2":String.valueOf(accountVersion), PayWayEnum.PAY_WAY_WEICHAT.getPayId());
        APIResponse<WeichatAccount> accountResp = payService.getWeichatAccount(accountVersion==null?"2":String.valueOf(accountVersion), PayWayEnum.PAY_WAY_WEICHAT.getPayId(),apply.getLarkAppId());
        if (!accountResp.isRet()) {
            return ;
        }
        WeichatAccount weichatAccount = accountResp.getData();

        //调用微信企业支付接口
        TransferFundReqData data = new TransferFundReqData();
        data.setMch_appid(weichatAccount.getAppId());
        data.setMchid(weichatAccount.getMchId());
        data.setOpenid(openid);
        data.setAmount(payAmount.intValue());
        data.setPartner_trade_no(withdrawNo);
        data.setNonce_str(com.quanyan.weichat.common.RandomStringGenerator.getRandomStringByLength(32));
        data.setRe_user_name(apply.getWithdrawUserName()); //强制校验提现人真实姓名
        data.setDesc(desc);
        data.setSpbill_create_ip("127.0.0.1");
        String sign = null;
        try {
            sign = Signature.getSign(data, weichatAccount.getWxKey());
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        data.setSign(sign);
        data.setSslCertificate(new ByteArrayInputStream(weichatAccount.getCertData()));
        WeichatServiceApi weichatServiceApi = new WeichatServiceApi();
        TransferFundResData resData = weichatServiceApi.transferFund(data);
        logger.info("调用微信付款，返回：{}", JSON.toJSON(resData));

        //处理付款结果
        WithdrawTransferNotify notify = new WithdrawTransferNotify();
        notify.setSourceSystemCode(apply.getSourceSystemCode());
        notify.setSourceBusinessCode(apply.getSourceBusinessCode());
        notify.setWithdrawNo(withdrawNo);
        notify.setApplyNo(apply.getWithdrawApplyNo());
        notify.setAmount(payAmount.divide(new BigDecimal(100), 2));    //回调返回单位为元
        notify.setAccountNo(openid);
        notify.setName(apply.getWithdrawUserName());
        notify.setCompletedTime(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));

        String resultCode = resData.getReturn_code();
        if ("SUCCESS".equals(resultCode)
                && "SUCCESS".equals(resData.getResult_code())) {
            //更新提现申请记录
            apply.setTsnNo(resData.getPayment_no());
            apply.setAuditStatus((byte) 1);
            apply.setStatus((byte) 2); //转账成功
            apply.setResult("付款成功");
            try {
                apply.setDealTime(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(resData.getPayment_time()));
            } catch (ParseException e) {
                e.printStackTrace();
            }
            apply.setPayAmount(payAmount.divide(new BigDecimal(100), 2));  //实际支付金额，变成元
            withdrawApplyMapper.updateByPrimaryKeySelective(apply);

            //发送MQ消息给业务系统，通知付款成功信息
            notify.setTsn(resData.getPayment_no());
            notify.setTag(true);
            notify.setReason("付款成功");
            //优先使用notify_url
            WithdrawApply applyWithdraw = withdrawApplyMapper.selectByPrimaryKey(Integer.valueOf(apply.getWithdrawNo()));
            notify.setNotifyUrl(applyWithdraw.getNotifyUrl());
            callBackByWithdraw(notify,OrderMqConstants.PAY_RESEND);
            //   sendNotify(apply.getNotifyUrl(), notify, resData.getNonce_str());

            //   return APIResponse.returnSuccess(resData.getPayment_no()); //企业付款成功，返回的微信订单号
            return ;
        } else {
            String error = resData.getResult_code() + resData.getErr_code_des();
            //更新提现申请记录
            apply.setAuditStatus((byte) 1);
            apply.setResult(error);
            if ("NOTENOUGH".equals(resData.getErr_code())||resData.getReturn_msg().equals("对同一用户转账操作过于频繁,请稍候重试.")
                    ||resData.getReturn_msg().equals("你的商户号未开通该产品权限，请联系管理员到产品中心开通")
                    ||resData.getReturn_msg().equals("网络繁忙[2476],请原单号再试.")
                    ||"SYSTEMERROR".equals(resData.getErr_code())
                    ||resData.getReturn_msg().equals("超过频率限制,请稍后再试")){ //内部原因，余额不足，可重新付款
                apply.setStatus((byte)3);
                withdrawApplyMapper.updateByPrimaryKeySelective(apply);
            }else {
                apply.setStatus((byte) 4); //外部原因，转账失败
                withdrawApplyMapper.updateByPrimaryKeySelective(apply);

                //发送MQ消息给业务系统，通知付款失败信息
                notify.setTag(false);
                notify.setReason(error);
                WithdrawApply applyWithdraw = withdrawApplyMapper.selectByPrimaryKey(Integer.valueOf(apply.getWithdrawNo()));
                notify.setNotifyUrl(applyWithdraw.getNotifyUrl());
                callBackByWithdraw(notify,OrderMqConstants.PAY_RESEND);
            }

            return ;
        }
    }

    @Override
    public APIResponse<PageObj<List<RespBatchWithdraw>>> batchWithdrawQuery(ReqBatchWithdrawQuery reqBatchWithdrawQuery) throws ParseException {
        if(!StringUtil.isBlankOrNull(reqBatchWithdrawQuery.getEndCreateTime())){
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
            Date endCreateTime=simpleDateFormat.parse(reqBatchWithdrawQuery.getEndCreateTime());
            endCreateTime=DateUtils.addTime(endCreateTime,1,DateUtils.TIME_TYPE_DAY);
            reqBatchWithdrawQuery.setEndCreateTime(simpleDateFormat.format(endCreateTime));
        }
        int count=eWithdrawBatchMapper.countBatchWithdrawQuery(reqBatchWithdrawQuery);
        Page page = Page.createPage(count, reqBatchWithdrawQuery.getPageNo(), reqBatchWithdrawQuery.getPageSize());
        reqBatchWithdrawQuery.setPageNo(reqBatchWithdrawQuery.getPageNo()*reqBatchWithdrawQuery.getPageSize());
        List<RespBatchWithdraw> respBatchWithdrawList = eWithdrawBatchMapper.batchWithdrawQuery(reqBatchWithdrawQuery);
        PageObj<List<RespBatchWithdraw>> pageObj = PageObj.create(count, reqBatchWithdrawQuery.getPageNo()/reqBatchWithdrawQuery.getPageSize(), reqBatchWithdrawQuery.getPageSize(), respBatchWithdrawList);
        return APIResponse.returnSuccess(pageObj);
    }

    @Override
    public APIResponse<List<RespWithdrawApply>> getApplyByBatchNo(String batchNo) {
        List<Integer> withdrawNo = new ArrayList<Integer>();
        //获取批次打款的记录
        WithdrawBatchExample withdrawBatchExample = new WithdrawBatchExample();
        withdrawBatchExample.createCriteria().andBatchNoEqualTo(batchNo);
        List<WithdrawBatch> withdrawBatchList = withdrawBatchMapper.selectByExample(withdrawBatchExample);
        if(withdrawBatchList.isEmpty()){ 
            return APIResponse.returnFail("无该批次记录");
        }
        //获取该批次的流水记录
        List<String> withdrawNoListt = Arrays.asList(withdrawBatchList.get(0).getWithdrawNos().split(","));
        List<WithdrawApply> withdrawApplyList = eWithdrawApplyMapper.selectApplyByWithdrawNos(withdrawNoListt);
        System.out.println(withdrawBatchList.get(0).getWithdrawNos());
        List<RespWithdrawApply> respWithdrawApplyList = new ArrayList<RespWithdrawApply>();
        for (WithdrawApply withdrawApply : withdrawApplyList){
            RespWithdrawApply apply = new RespWithdrawApply();
            apply.setAccountNo(withdrawApply.getWithdrawAccountNo());
            apply.setAmount(withdrawApply.getWithdrawAmount());
            apply.setApplyNo(withdrawApply.getWithdrawApplyNo());
            apply.setApplyTime(withdrawApply.getWithdrawApplyTime());
            String syscode = withdrawApply.getSourceSystemCode();
            if (Constants.CLUB_SYSTEM_CODE.equals(syscode)){
                apply.setModuleId(1);
            }
            if (Constants.AUCTION_SYSTEM_CODE.equals(syscode)){
                apply.setModuleId(2);
            }
            if (Constants.ONEPRICE_SYSTEM_CODE.equals(syscode)){
                apply.setModuleId(3);
            }

            apply.setPayType(withdrawApply.getPayType());
            apply.setRealName(withdrawApply.getWithdrawUserName());
            apply.setStatus(withdrawApply.getStatus());
            apply.setBalance(withdrawApply.getBalance());
            apply.setRemark(withdrawApply.getRemark());
            apply.setPhone(withdrawApply.getPhone());
            apply.setWithdrawNo(String.valueOf(withdrawApply.getWithdrawNo()));
            apply.setResult(withdrawApply.getResult());
            apply.setPayOpInfo(withdrawApply.getPayOpInfo());
            apply.setPayAmount(withdrawApply.getPayAmount());
            apply.setCreateTime(withdrawApply.getCreateTime());
            apply.setUpdateTime(withdrawApply.getUpdateTime());
            apply.setClubId(withdrawApply.getClubId());
            respWithdrawApplyList.add(apply);
        }
        return APIResponse.returnSuccess(respWithdrawApplyList);
    }

    private Boolean updateWithdrawApplyByWeChat(Integer withdrawNo) {
        WithdrawApply withdrawApply = new WithdrawApply();
        withdrawApply.setStatus((byte)1);
        WithdrawApplyExample withdrawApplyExample = new WithdrawApplyExample();
        withdrawApplyExample.createCriteria().andStatusEqualTo((byte)5).andWithdrawNoEqualTo(withdrawNo);
        int count=withdrawApplyMapper.updateByExampleSelective(withdrawApply,withdrawApplyExample);
        //未申请提现的
        if(count==0){
            return false;
        }else {
            return true;
        }
    }

    private void sendNotify(String notifyUrl, WithdrawTransferNotify notify, String messageId){
        if (!StringUtil.isBlankOrNull(notifyUrl)) {     //如果有回调url，优先使用过会的url
            try {
                HttpClientUtils.postJson(notifyUrl, JSON.toJSONString(notify));
            } catch (Exception e) {
                logger.error("发送提现付款通知失败！{}", e.getMessage());
            }
            logger.info("发送提现付款回调消息：{}", JSON.toJSONString(notify));
        }else {
            MqRequestMsg mqRequestMsg = new MqRequestMsg();
            mqRequestMsg.setTopic(OrderPayService.TOPIC_WITHDRAW_CALLBACK_NOTIFY);
            mqRequestMsg.setTag("*");
            mqRequestMsg.setMsgId(messageId);
            mqRequestMsg.setFlag(0);
            mqRequestMsg.setBody(ObjectUtil.toByteArray(notify));
            qcMsgClient.asyncSend(mqRequestMsg);
            logger.info("发送提现付款回调消息：{}", JSON.toJSONString(notify));
        }
    }

}
